﻿using System.Collections.Generic;
using System.Runtime.Serialization;
using MyFloridaHouse.ServiceConn.DistrBldrSvcRef;
using System;
using System.Text;

namespace MyFloridaHouse.libSvOpenDistricts.Census
{
    
    [DataContract(IsReference = true)]
    public class CensusGeometryNode
    {

        public static int maxDojIDLength = 15; //NOTE: doj00 field size is defined as in database

        const int databaseNull = -1;

        private bool _isLocked = false;
        [DataMember]
        public bool isLocked
        {
            get { return _isLocked; }
            set { _isLocked = value; }
        }

        private int _parentuogID;
        [DataMember]
        public int parentuogID { set { _parentuogID = value; } get { return _parentuogID; } }

        private List<CensusGeometryNode> _childNodeList;
        [DataMember]
        public List<CensusGeometryNode> childNodeList { set { _childNodeList = value; } get { return _childNodeList; } }

        private int _districtID = 0;
        [DataMember]
        public int districtID { set { _districtID = value; } get { return _districtID; } }

        private string _doj00;
        [DataMember]
        public string doj00 { set { _doj00 = value; } get { return _doj00; } }

        private int _uogID;
        [DataMember]
        public int uogID { set { _uogID = value; } get { return _uogID; } }

        private int _uogType;
        [DataMember]
        public int uogType { set { _uogType = value; } get { return _uogType; } } // todo: uogType should be an enumeration

        private int _layerID;
        [DataMember]
        public int layerID { set { _layerID = value; } get { return _layerID; } }

        private int _regionID;
        [DataMember]
        public int regionID { set { _regionID = value; } get { return _regionID; } }

        // Constructor
        public CensusGeometryNode()
        {
        }

        public CensusGeometryNode( CensusGeometryDTO dto)
        {
            // set up the node data
            if (dto.parentUogID == databaseNull)
                parentuogID = -1;
            else
                parentuogID = dto.parentUogID;
            childNodeList = new List<CensusGeometryNode>();
            if (null == dto.doj00)
            {
                dto.doj00 = " ";
            }
            doj00 = dto.doj00;
            uogID = dto.uogID;
            uogType = dto.uogType;
            layerID = dto.layerID;
            regionID = dto.regionID;
            districtID = CensusGeometryConstants.unassignedDistrictID;

        }

        public static int CensusGeometryStorageNodeSize = 24; // total number of bytes used by this structure when converted to bytes
        // 4, ints = 4*4 bytes
        // 1 uint64 = 8 bytes 
        // total 16 + 8 = 24
        // restriction is that dojID must fit into 8 bytes.  (which at max 15 characters it does)
        // NOTE:  null is not allowed as a value for doj00

        public static void GetBytes(CensusGeometryNode node, Byte[] destinationArray, int offset)
        {
            Buffer.BlockCopy(BitConverter.GetBytes(node.uogID), 0, destinationArray, offset, sizeof(int)); offset += sizeof(int);
            Buffer.BlockCopy(BitConverter.GetBytes(node.parentuogID), 0, destinationArray, offset, sizeof(int)); offset += sizeof(int);
            Buffer.BlockCopy(BitConverter.GetBytes(node.uogType), 0, destinationArray, offset, sizeof(int)); offset += sizeof(int);
            Buffer.BlockCopy(BitConverter.GetBytes(node.layerID), 0, destinationArray, offset, sizeof(int)); offset += sizeof(int);
            Buffer.BlockCopy(ConvertDOJStringToUInt64WithValidation(node.doj00), 0, destinationArray, offset, sizeof(UInt64)); offset += sizeof(UInt64);
        }

        public static CensusGeometryNode GetCensusGeometryNode(byte[] sourceByteArray, int offset)
        {
            CensusGeometryNode newNode = new CensusGeometryNode();
            newNode.uogID = BitConverter.ToInt32(sourceByteArray, offset); offset += sizeof(int);
            newNode.parentuogID = BitConverter.ToInt32(sourceByteArray, offset); offset += sizeof(int);
            newNode.uogType = BitConverter.ToInt32(sourceByteArray, offset); offset += sizeof(int);
            newNode.layerID = BitConverter.ToInt32(sourceByteArray, offset); offset += sizeof(int);
            newNode.doj00 = GetDOJStringFromBytes(BitConverter.ToUInt64(sourceByteArray, offset)); offset += sizeof(UInt64);
            return newNode;
        }

        private static string GetDOJStringFromBytes(UInt64 dojUint64)
        {
            string doj = Convert.ToString(dojUint64).Trim();
            if ("0" == doj)
            {
                doj = " ";
            }
            return doj;
        }

        internal static byte[] ConvertDOJStringToUInt64WithValidation(string doj)
        {
            string convertDOJ = doj;
            if (string.Empty == doj.Trim())
            {
                convertDOJ = "0";
            }
            // convert to bytes
            ulong DOJulong;
            if (!ulong.TryParse(convertDOJ, out DOJulong))
            {
                throw new Exception("Unable to convert dojID [" + doj + "] to storage format, parse failed");
            }

            // our final product!
            byte[] dojBytes = BitConverter.GetBytes(DOJulong);

            // now, to verify, convert back and compare to original string
            if (doj != GetDOJStringFromBytes(BitConverter.ToUInt64(dojBytes, 0)))
            {
                throw new Exception("Unable to convert dojID [" + doj +"] to storage format, validation failed");
            }
            return dojBytes;
        }

    }
}
